<?php

namespace addons\workorder\library;

use think\Db;
use think\Hook;
use think\Lang;
use think\Request;
use think\Validate;
use think\Exception;
use app\common\library\Email;
use think\exception\PDOException;
use app\common\library\Sms as Smslib;
use addons\workorder\model\Orders;
use addons\workorder\model\Records;
use addons\workorder\model\Engineer;

class General
{
    protected static $instance        = null;
    protected static $fileField       = ['image', 'images', 'file', 'files'];
    protected static $imgArr          = ['jpg', 'png', 'bmp', 'jpeg', 'gif'];
    protected        $workorderConfig = [];

    public function __construct()
    {
        $this->workorderConfig                = get_addon_config('workorder');
        $this->workorderConfig['notice_mail'] = isset($this->workorderConfig['notice_mail']) ? explode(',', $this->workorderConfig['notice_mail']) : [];
        $this->workorderConfig['notice_sms']  = isset($this->workorderConfig['notice_sms']) ? explode(',', $this->workorderConfig['notice_sms']) : [];

        Lang::load(ROOT_PATH . 'addons' . DS . 'workorder' . DS . 'lang' . DS . Request::instance()->langset() . '.php');
    }

    public static function instance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new static();
        }

        return self::$instance;
    }

    /**
     * 计算一个工程师的平均回复时间
     * 通常在有新的回复时调用
     * @param int $engineerId 工程师ID
     * @return float
     * @throws Exception
     * @throws PDOException
     */
    public static function calcEngineerAvgResTime($engineerId)
    {
        $workorderTimeStatistics = Db::name('workorder_time_statistics')
            ->alias('s')
            ->join('workorder_orders o', 'o.id=s.order_id')
            ->where('o.deletetime', null)
            ->where('s.type', 'in', '1,2')
            ->where('s.engineer_id', $engineerId)
            ->where('s.time_consum', '>', '0')
            ->avg('s.time_consum');

        Db::name('workorder_engineers')->where('id', $engineerId)->update([
            'avg_response_time' => ceil($workorderTimeStatistics)
        ]);

        return $workorderTimeStatistics;
    }


    public static function orderNumberChangeCalcEngineerStatistics($orderId, $engineer = false, $type = 'del')
    {
        if ($engineer) {
            self::calcEngineerAvgResTime($engineer);
        }

        // 沟通记录
        $records = Records::where('order_id', $orderId)
            ->order('createtime asc')
            ->select();

        // 共有哪些工程师
        $engineers = [];
        if ($engineer) {
            $engineers[$engineer] = $engineer;
        }

        foreach ($records as $record) {
            if ($record->engineer_id) {
                $engineers[$record->engineer_id] = $record->engineer_id;
            }
        }

        $engineers = Engineer::select($engineers);
        Db::startTrans();
        try {
            if ($type == 'del') {
                foreach ($engineers as $item) {
                    $item->work_order_quantity--;
                    $item->save();
                }
            } elseif ($type == 'restore') {
                foreach ($engineers as $item) {
                    $item->work_order_quantity++;
                    $item->save();
                }
            }
            Db::commit();
        } catch (PDOException|Exception $e) {
            Db::rollback();
            return false;
        }
        return true;
    }

    public function autoClose()
    {
        if ($this->workorderConfig['auto_close'] == 0) {
            return true;
        }

        $nowTime = time();

        $orders = Orders::all(['status' => '3']);
        foreach ($orders as $order) {
            $userLastRecordTime = Records::where('order_id', $order->id)
                ->where('user_id', '>', 0)
                ->order('createtime desc')
                ->value('createtime');
            $autoCloseTime      = $userLastRecordTime + (int)($this->workorderConfig['auto_close'] * 3600);
            if ($autoCloseTime <= time()) {
                $order->status = '4';
                $order->save();
                $record = [
                    'order_id'     => $order->id,
                    'engineer_id'  => $order->engineer_id,
                    'message_type' => 3,
                    'message'      => __('The job has been closed automatically!')
                ];
                Records::create($record);

                // 记录结单耗时
                $timeStatistics = Db::name('workorder_time_statistics')
                    ->where('order_id', $order->id)
                    ->where('type', 0)
                    ->where('time_consum', null)
                    ->find();
                if ($timeStatistics) {
                    Db::name('workorder_time_statistics')->where('id', $timeStatistics['id'])->update([
                        'endtime'     => $nowTime,
                        'time_consum' => $nowTime - $timeStatistics['starttime'],
                        'engineer_id' => $order->engineer_id,// 防转移，冲正为当前工程师
                    ]);
                }
            }
        }
        return true;
    }

    /**
     * 发送邮件通知
     */
    public function mailNotice($row, $event, $subject, $message)
    {

        if (!in_array($event, $this->workorderConfig['notice_mail'])) {
            return false;
        }

        if ($event == 'user_order_handle' || $event == 'user_got_reply') {
            if (!isset($row->email) || !isset($row->remind) || !$row->email || ($row->remind != 2)) {
                return false;
            }
        } else {
            if (!$row->engineer_id) {
                return false;
            }
            $row        = Engineer::get($row->engineer_id);
            $row->email = $row->user->email;
        }

        if (!Validate::is($row->email, "email")) {
            return false;
        }
        $email  = new Email;
        $result = $email->to($row->email)
            ->subject($subject)
            ->message('<div style="min-height:550px; padding: 100px 55px 200px;">' . $message . '</div>')
            ->send();

        if ($result) {
            return true;
        } else {
            //$email->getError();
            return false;
        }
    }

    /**
     * 发送短信通知
     */
    public function smsNotice($row, $event)
    {
        if (!in_array($event, $this->workorderConfig['notice_sms'])) {
            return false;
        }

        // 最多12个字符
        $msg = mb_strlen($row->title) > 12 ? mb_substr($row->title, 0, 9) . '...' : $row->title;

        // 兼容短信宝和创蓝
        $smsbao = get_addon_info('smsbao');
        $clsms  = get_addon_info('clsms');
        if (($smsbao && $smsbao['state'] == 1) || ($clsms && $clsms['state'] == 1)) {
            switch ($event) {
                case 'user_order_handle':
                    $msg = __('The engineer has viewed the work order you submitted:%s and is processing it.', [$msg]);
                    break;
                case 'user_got_reply':
                    $msg = __('The engineer has replied to your work order:%s, please check the feedback in time.', [$msg]);
                    break;
                case 'engineer_new_order':
                    $msg = __('Dear engineer, you have received a new work order:%s, please handle it in time.', [$msg]);
                    break;
                case 'engineer_got_reply':
                    $msg = __('Dear engineer, work order:%s, user feedback has been received, please handle it in time.', [$msg]);
                    break;
                case 'engineer_urging':
                    $msg = __('Dear engineer, work order:%s, the user hopes you will reply as soon as possible.', [$msg]);
                    break;
                default:
                    $msg = __('Sending scenario not recognized by the work order system');
                    break;
            }
        }

        if ($event == 'user_order_handle' || $event == 'user_got_reply') {
            if (!isset($row->mobile) || !isset($row->remind) || !$row->mobile || ($row->remind != 1)) {
                return false;
            }
        } else {
            if (!$row->engineer_id) {
                return false;
            }
            $row         = Engineer::get($row->engineer_id);
            $row->mobile = $row->user->mobile;
        }

        if (!$row->mobile || !Validate::regex($row->mobile, "^1\d{10}$")) {
            return false;
        }

        if (!Hook::get('sms_send')) {
            return false;
        }

        // 兼容创蓝
        if ($clsms && $clsms['state'] == 1) {
            $clsms  = new \addons\clsms\library\Clsms();
            $result = $clsms->smstype(0)->mobile($row->mobile)->msg($msg)->send();
            if ($result) {
                return true;
            } else {
                return false;
            }
        }

        // 兼容阿里云短信
        $alisms = get_addon_info('alisms');
        if ($alisms && $alisms['state'] == 1) {
            $params = [
                'mobile' => $row->mobile,
                'msg'    => [
                    'title' => $msg
                ],
                'event'  => $event
            ];
            $ret    = Hook::listen('sms_notice', $params, null, true);
        } else {
            $ret = Smslib::notice($row->mobile, $msg, $event);
        }

        if ($ret) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取文件后缀
     * @param string $filename 文件路径/名称
     * @return string
     */
    public static function getFileExtension($filename)
    {
        $filename = explode('.', $filename);
        return end($filename);
    }

    /**
     * 生成文件后缀图片
     * @param string $suffix 后缀
     * @param null   $background
     * @return string
     */
    public static function buildSuffixImage($suffix, $background = null)
    {
        $suffix = mb_substr(strtoupper($suffix), 0, 4);
        $total  = unpack('L', hash('adler32', $suffix, true))[1];
        $hue    = $total % 360;
        list($r, $g, $b) = hsv2rgb($hue / 360, 0.3, 0.9);

        $background = $background ?: "rgb($r,$g,$b)";

        $icon = <<<EOT
        <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
            <path style="fill:#E2E5E7;" d="M128,0c-17.6,0-32,14.4-32,32v448c0,17.6,14.4,32,32,32h320c17.6,0,32-14.4,32-32V128L352,0H128z"/>
            <path style="fill:#B0B7BD;" d="M384,128h96L352,0v96C352,113.6,366.4,128,384,128z"/>
            <polygon style="fill:#CAD1D8;" points="480,224 384,128 480,128 "/>
            <path style="fill:{$background};" d="M416,416c0,8.8-7.2,16-16,16H48c-8.8,0-16-7.2-16-16V256c0-8.8,7.2-16,16-16h352c8.8,0,16,7.2,16,16 V416z"/>
            <path style="fill:#CAD1D8;" d="M400,432H96v16h304c8.8,0,16-7.2,16-16v-16C416,424.8,408.8,432,400,432z"/>
            <g><text><tspan x="220" y="380" font-size="124" font-family="Verdana, Helvetica, Arial, sans-serif" fill="white" text-anchor="middle">{$suffix}</tspan></text></g>
        </svg>
EOT;
        return $icon;
    }

    /**
     * 清理xss
     * @param string $val
     * @return string
     */
    public static function removeXss($val)
    {
        if (!$val) {
            return '';
        }
        if (function_exists('xss_clean')) {
            return xss_clean($val);
        }

        $val = preg_replace('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/', '', $val);

        $search = 'abcdefghijklmnopqrstuvwxyz';
        $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $search .= '1234567890!@#$%^&*()';
        $search .= '~`";:?+/={}[]-_|\'\\';
        for ($i = 0; $i < strlen($search); $i++) {
            $val = preg_replace('/(&#[xX]0{0,8}' . dechex(ord($search[$i])) . ';?)/i', $search[$i], $val); // with a ;
            $val = preg_replace('/(&#0{0,8}' . ord($search[$i]) . ';?)/', $search[$i], $val); // with a ;
        }

        $ra1   = [
            'javascript',
            'vbscript',
            'expression',
            'applet',
            'meta',
            'xml',
            'blink',
            'link',
            'style',
            'script',
            'embed',
            'object',
            'iframe',
            'frame',
            'frameset',
            'ilayer',
            'layer',
            'bgsound',
            'title',
            'base'
        ];
        $ra2   = [
            'onabort',
            'onactivate',
            'onafterprint',
            'onafterupdate',
            'onbeforeactivate',
            'onbeforecopy',
            'onbeforecut',
            'onbeforedeactivate',
            'onbeforeeditfocus',
            'onbeforepaste',
            'onbeforeprint',
            'onbeforeunload',
            'onbeforeupdate',
            'onblur',
            'onbounce',
            'oncellchange',
            'onchange',
            'onclick',
            'oncontextmenu',
            'oncontrolselect',
            'oncopy',
            'oncut',
            'ondataavailable',
            'ondatasetchanged',
            'ondatasetcomplete',
            'ondblclick',
            'ondeactivate',
            'ondrag',
            'ondragend',
            'ondragenter',
            'ondragleave',
            'ondragover',
            'ondragstart',
            'ondrop',
            'onerror',
            'onerrorupdate',
            'onfilterchange',
            'onfinish',
            'onfocus',
            'onfocusin',
            'onfocusout',
            'onhelp',
            'onkeydown',
            'onkeypress',
            'onkeyup',
            'onlayoutcomplete',
            'onload',
            'onlosecapture',
            'onmousedown',
            'onmouseenter',
            'onmouseleave',
            'onmousemove',
            'onmouseout',
            'onmouseover',
            'onmouseup',
            'onmousewheel',
            'onmove',
            'onmoveend',
            'onmovestart',
            'onpaste',
            'onpropertychange',
            'onreadystatechange',
            'onreset',
            'onresize',
            'onresizeend',
            'onresizestart',
            'onrowenter',
            'onrowexit',
            'onrowsdelete',
            'onrowsinserted',
            'onscroll',
            'onselect',
            'onselectionchange',
            'onselectstart',
            'onstart',
            'onstop',
            'onsubmit',
            'onunload'
        ];
        $ra    = array_merge($ra1, $ra2);
        $found = true;
        while ($found == true) {

            $val_before = $val;
            for ($i = 0; $i < sizeof($ra); $i++) {
                $pattern = '/';
                for ($j = 0; $j < strlen($ra[$i]); $j++) {
                    if ($j > 0) {
                        $pattern .= '(';
                        $pattern .= '(&#[xX]0{0,8}([9ab]);)';
                        $pattern .= '|';
                        $pattern .= '|(&#0{0,8}([9|10|13]);)';
                        $pattern .= ')*';
                    }
                    $pattern .= $ra[$i][$j];
                }
                $pattern     .= '/i';
                $replacement = substr($ra[$i], 0, 2) . '<k>' . substr($ra[$i], 2);
                $val         = preg_replace($pattern, $replacement, $val);
                if ($val_before == $val) {
                    $found = false;
                }
            }
        }
        return $val;
    }

    public static function createOrder($row, $userId)
    {
        $fields  = Orders::getFields(null, 0);
        $records = [];

        // 要入沟通记录的字段-所有文件自动入沟通记录
        $otherField  = '';
        $recordField = [
            'describe'     => '0',// 描述-富文本
            'confidential' => '4',// 机密信息-机密信息
        ];
        foreach ($fields as $field) {
            if ($field['isrequire'] && $field['type_list'] != 'text' && (!isset($row[$field['name']]) || $row[$field['name']] == '')) {
                return ['code' => 0, 'msg' => __('%s can not be empty!', $field['title'])];
            }

            if (isset($row[$field['name']]) && is_array($row[$field['name']])) {
                $row[$field['name']] = implode(',', $row[$field['name']]);
            }

            if ($field['type_list'] == 'editor') {
                $fieldOrigin = Request::instance()->param($field['name'], '', 'trim');
                if (!$fieldOrigin) {
                    $fieldOrigin = Request::instance()->param('row/a', '', 'trim');
                    $fieldOrigin = $fieldOrigin[$field['name']] ?? '';
                }
                $row[$field['name']] = self::removeXss($fieldOrigin);
            }

            // 将uniapp端的城市名与数据库中的进行兼容
            if ($field['type_list'] == 'city' && isset($row[$field['name']]) && $row[$field['name']]) {
                $city = explode('/', $row[$field['name']]);
                if ($city && mb_strpos($city[0], '市') !== false) {
                    $city[1]             = $city[0];
                    $city[0]             = mb_substr($city[0], 0, mb_strlen($city[0]) - 1);
                    $row[$field['name']] = implode('/', $city);
                }
            }

            if (array_key_exists($field['name'], $recordField) && isset($row[$field['name']]) && $row[$field['name']]) {
                $records[] = [
                    'user_id'      => $userId,
                    'message_type' => $recordField[$field['name']],
                    'message'      => $row[$field['name']]
                ];
            }

            if (in_array($field['type_list'], self::$fileField) && isset($row[$field['name']]) && $row[$field['name']]) {
                $attachment   = explode(',', trim($row[$field['name']], ','));
                $message_type = ($field['type_list'] == 'image' || $field['type_list'] == 'images') ? 1 : 2;

                foreach ($attachment as $item) {

                    $itemInfo = pathinfo($item);
                    if (in_array($itemInfo['extension'], self::$imgArr)) {
                        $message_type = 1;
                    }

                    $records[] = [
                        'user_id'      => $userId,
                        'message_type' => $message_type,
                        'message'      => $item
                    ];
                }
            }

            // 非聊天记录字段且非文件字段且非基本信息字段，对值进行格式化后写入聊天记录
            if (!array_key_exists($field['name'], $recordField) && !in_array($field['type_list'], self::$fileField) && !$field['isbasicinfo']) {
                $fieldValue = self::fieldValue($field, $row[$field['name']]);
                if ($fieldValue) {
                    $otherField .= $field['title'] . '：' . $fieldValue . '<br />';
                }
            }
        }

        if ($otherField) {
            $records[] = [
                'user_id'      => $userId,
                'message_type' => 0,
                'message'      => $otherField
            ];
        }

        $row['user_id']    = $userId;
        $row['status']     = 0;
        $row['createtime'] = time();
        $row['updatetime'] = time();

        try {
            $order = Orders::create($row);
            if ($records) {
                foreach ($records as $index => $record) {
                    $records[$index]['batch']    = 1;
                    $records[$index]['order_id'] = $order->id;
                }
                $recordsModel = new Records;
                $recordsModel->saveAll($records);
            }

            // 分派工单
            $General    = General::instance();
            $engineerId = $General->distribution($order, $userId);

            // 准备记录结单和首回耗时
            $timeStatistics[0]         = [
                'type'        => 0,
                'order_id'    => $order->id,
                'engineer_id' => $engineerId,
                'starttime'   => time()
            ];
            $timeStatistics[1]         = $timeStatistics[0];
            $timeStatistics[1]['type'] = 2;
            Db::name('workorder_time_statistics')->insertAll($timeStatistics);

        } catch (Exception $e) {
            return ['code' => 0, 'msg' => 'error:' . $e->getMessage()];
        }

        return [
            'code' => 1,
            'data' => ['id' => $order->id]
        ];
    }

    public static function formatFileSize($num)
    {
        $p      = 0;
        $format = 'bytes';
        if ($num > 0 && $num < 1024) {
            return number_format($num) . ' ' . $format;
        }
        if ($num >= 1024 && $num < pow(1024, 2)) {
            $p      = 1;
            $format = 'KB';
        }
        if ($num >= pow(1024, 2) && $num < pow(1024, 3)) {
            $p      = 2;
            $format = 'MB';
        }
        if ($num >= pow(1024, 3) && $num < pow(1024, 4)) {
            $p      = 3;
            $format = 'GB';
        }
        if ($num >= pow(1024, 4) && $num < pow(1024, 5)) {
            $p      = 3;
            $format = 'TB';
        }
        $num /= pow(1024, $p);
        return number_format($num, 2) . ' ' . $format;
    }

    public function createEvaluate($order, $row, $userId)
    {
        $nowTime = time();
        if (!$row['stars']) {
            return ['code' => 0, 'msg' => __('Please select the overall evaluation~')];
        } elseif (!isset($row['solved'])) {
            return ['code' => 0, 'msg' => __('Please select whether the problem has been solved~')];
        }

        $row['order_id']    = $order->id;
        $row['category_id'] = $order->category_id;
        $row['user_id']     = $userId;
        $row['createtime']  = $nowTime;

        if (Db::name('workorder_evaluate')->insert($row)) {
            $order->status = 5;
            $order->save();

            // 记录结单耗时
            $timeStatistics = Db::name('workorder_time_statistics')
                ->where('order_id', $order->id)
                ->where('type', 0)
                ->where('time_consum', null)
                ->find();
            if ($timeStatistics) {
                Db::name('workorder_time_statistics')->where('id', $timeStatistics['id'])->update([
                    'endtime'     => $nowTime,
                    'time_consum' => $nowTime - $timeStatistics['starttime'],
                    'engineer_id' => $order->engineer_id,// 防转移，冲正为当前工程师
                ]);
            }
            return ['code' => 1, 'msg' => __('Evaluation submitted successfully~')];
        } else {
            return ['code' => 0, 'msg' => __('Evaluation failed, please try again!')];
        }
    }

    /**
     * 回复工单
     */
    public function createReply($order, $user, $engineer, $row)
    {
        $nowTime    = time();
        $replyField = $order->getFields(null, $user ? 1 : 2);

        // 要入沟通记录的字段-所有文件自动入沟通记录
        $recordField = [
            'reply_describe'     => '0',// 描述-富文本
            'reply_confidential' => '4',// 机密信息-机密信息
        ];
        $records     = [];
        $otherField  = '';

        foreach ($replyField as $field) {
            if ($field['isrequire'] && (!isset($row[$field['name']]) || $row[$field['name']] == '')) {
                return ['code' => 0, 'msg' => __('%s can not be empty!', $field['title'])];
            }

            if ($field['type_list'] == 'editor') {
                $fieldOrigin = Request::instance()->param($field['name'], '', 'trim');
                if (!$fieldOrigin) {
                    $fieldOrigin = Request::instance()->param('row/a', '', 'trim');
                    $fieldOrigin = $fieldOrigin[$field['name']] ?? '';
                }
                $row[$field['name']] = self::removeXss($fieldOrigin);
            }

            if (array_key_exists($field['name'], $recordField) && isset($row[$field['name']]) && $row[$field['name']]) {
                $records[] = [
                    'message_type' => $recordField[$field['name']],
                    'message'      => $row[$field['name']]
                ];
            }

            if (in_array($field['type_list'], self::$fileField) && isset($row[$field['name']]) && $row[$field['name']]) {
                $attachment   = explode(',', trim($row[$field['name']], ','));
                $message_type = ($field['type_list'] == 'image' || $field['type_list'] == 'images') ? 1 : 2;

                foreach ($attachment as $item) {
                    $itemInfo = pathinfo($item);
                    if (in_array($itemInfo['extension'], self::$imgArr)) {
                        $message_type = 1;
                    }
                    $records[] = [
                        'message_type' => $message_type,
                        'message'      => $item
                    ];
                }
            }

            // 非回复字段且非文件字段，对值进行格式化后写入聊天记录
            if (!array_key_exists($field['name'], $recordField) && !in_array($field['type_list'], self::$fileField)) {
                $fieldValue = self::fieldValue($field, $row[$field['name']]);
                if ($fieldValue) {
                    $otherField .= $field['title'] . '：' . $fieldValue . '<br />';
                }
            }
        }

        if ($otherField) {
            $records[] = [
                'message_type' => 0,
                'message'      => $otherField
            ];
        }

        $batch = Records::where('order_id', $order->id)->max('batch');

        foreach ($records as $index => $record) {
            $records[$index]['order_id'] = $order->id;
            $records[$index]['batch']    = $batch + 1;
            if ($user) {
                $records[$index]['sender']   = 'user';
                $records[$index]['user_id']  = $user->id;
                $records[$index]['nickname'] = $user->nickname;
                $records[$index]['avatar']   = cdnurl($user->avatar, true);
            } elseif ($engineer) {
                $records[$index]['sender']      = 'engineer';
                $records[$index]['engineer_id'] = $engineer->id;
                $records[$index]['title']       = $engineer->title;
                $records[$index]['avatar']      = ($engineer->user && $engineer->user->avatar) ? cdnurl($engineer->user->avatar, true) : (function_exists('letter_avatar') ? letter_avatar($engineer->title) : cdnurl('/assets/img/avatar.png', true));
            }
        }

        $recordsModel = new Records;
        $records      = $recordsModel->allowField(true)->saveAll($records);
        if ($records) {
            $timeStatistics = Db::name('workorder_time_statistics')
                ->where('order_id', $order->id)
                ->where('type', 'in', '1,2')
                ->where('time_consum', null)
                ->find();

            $order->title = $order->title ?? __('Untitled');

            if ($engineer) {
                if ($order->status == 2) {
                    $order->status = 3;

                    $this->mailNotice($order, 'user_got_reply', __('[new reply received for work order]') . $order->title, __('Work order:%s the engineer has replied to your question. Please check / feed back in time.', [$order->title]));
                    $this->smsNotice($order, 'user_got_reply');
                }
                if ($order->lasturgingtime) {
                    $order->lasturgingtime = null;
                }
                // 计算回复时间
                if ($timeStatistics) {
                    Db::name('workorder_time_statistics')->where('id', $timeStatistics['id'])->update([
                        'endtime'     => $nowTime,
                        'time_consum' => $nowTime - $timeStatistics['starttime'],
                        'engineer_id' => $order->engineer_id,// 防转移，冲正为当前工程师
                    ]);
                    $this->calcEngineerAvgResTime($order->engineer_id);
                }
            } else {
                if ($order->status == 3) {
                    $order->status = 2;

                    $this->mailNotice($order, 'engineer_got_reply', __('[work order receives new feedback]') . $order->title, __('Work order:%s the user has fed back new information, please check / reply in time.', [$order->title]));
                    $this->smsNotice($order, 'engineer_got_reply');
                }

                // 准备记录回复时间
                if (!$timeStatistics) {
                    $timeStatistics = [
                        'type'        => 1,
                        'order_id'    => $order->id,
                        'engineer_id' => $order->engineer_id,
                        'starttime'   => time()
                    ];
                    Db::name('workorder_time_statistics')->insert($timeStatistics);
                }
            }
            $order->allowField(true)->save();

            return [
                'code' => 1,
                'msg'  => __('Reply Success~'),
                'data' => [
                    'records' => $records
                ]
            ];
        }

        return ['code' => 0, 'msg' => __('Nothing happened~')];
    }

    public function transfer($order, $transferEngineer)
    {
        $engineer = Engineer::get($transferEngineer);

        if (!$engineer->user_id) {
            return ['code' => 0, 'msg' => __('The engineer has not bound users!')];
        }
        if ($engineer->user_id == $order->user_id) {
            return ['code' => 0, 'msg' => __('Engineer and issuer cannot be the same person!')];
        }
        if ($engineer && $engineer->status == '1') {
            $order->engineer_id = $transferEngineer;
            $order->save();

            $engineer->lastreceivetime = time();
            $engineer->work_order_quantity++;
            $engineer->save();

            $record = [
                'order_id'     => $order->id,
                'engineer_id'  => $transferEngineer,
                'message_type' => 3,
                'message'      => __('The work order has been transferred to:%s', $engineer->title)
            ];
            Records::create($record);
            return ['code' => 1, 'msg' => __('Work order transferred~')];
        }
        return ['code' => 0, 'msg' => __('Nothing happened~')];
    }

    public function distribution($order, $userId)
    {
        if (isset($order->engineer_id) && $order->engineer_id) {
            return false;
        } elseif (!$order->category_id) {
            return false;
        }

        $distribution_engineer = null;
        $where['status']       = '1';
        $where['user_id']      = ['<>', $userId];

        if ($this->workorderConfig['distribution_type'] == 2) {
            // 技能分派-循环
            $category_engineer = Db::name('workorder_category')->where('id', $order->category_id)->value('we_ids');
            if (!$category_engineer) {
                return false;
            }
            $where['id']                                = ['in', $category_engineer];
            $this->workorderConfig['distribution_type'] = 0;
        } elseif ($this->workorderConfig['distribution_type'] == 3) {
            // 技能分派-负载
            $category_engineer = Db::name('workorder_category')->where('id', $order->category_id)->value('we_ids');
            if (!$category_engineer) {
                return false;
            }
            $where['id']                                = ['in', $category_engineer];
            $this->workorderConfig['distribution_type'] = 1;
        }

        if ($this->workorderConfig['distribution_type'] == 0) {
            $distribution_engineer = Engineer::where($where)->order('lastreceivetime asc')->find();
        } elseif ($this->workorderConfig['distribution_type'] == 1) {

            $engineer = Engineer::where($where)->select();
            foreach ($engineer as $item) {
                $orderNumber = Orders::where('engineer_id', $item->id)->count();
                if ($orderNumber == 0) {
                    $distribution_engineer = $item;
                    break;
                } else {
                    if (isset($minOrder)) {
                        if ($orderNumber < $minOrder) {
                            $minOrder = $orderNumber;
                        }
                    } else {
                        $distribution_engineer = $item;
                        $minOrder              = $orderNumber;
                    }
                }
            }
        }

        if (!$distribution_engineer) {
            return false;
        }

        $distribution_engineer->lastreceivetime = time();
        $distribution_engineer->work_order_quantity++;
        $distribution_engineer->save();
        $order->engineer_id = $distribution_engineer->id;
        $order->status      = 1;
        $order->save();

        // 发送通知
        if (isset($order->title)) {
            $this->mailNotice($order, 'engineer_new_order', __('[new work order]') . $order->title, __('The user submitted a new job:%s please process it as soon as possible.', [$order->title]));
            $this->smsNotice($order, 'engineer_new_order');
        }
        return $distribution_engineer->id;
    }

    public static function handleUrl($url, $category)
    {
        if (preg_match('/^https?:\/\//i', $url)) {
            if (strpos($url, '?') === false) {
                $url .= '?category=' . $category;
            } else {
                $url .= '&category=' . $category;
            }
            return $url;
        } else {
            return url($url, ['category' => $category]);
        }
    }

    /**
     * 推荐知识点
     */
    public static function recKbs($id, $category = false, $limit = 20)
    {
        $recKbs = [];
        if ($category) {
            $kbsIds = Db::name('workorder_category')
                ->where('id', $category)
                ->where('status', '1')
                ->where('deletetime', null)
                ->value('kbs_ids');
            if ($kbsIds) {
                $recKbs = Db::name('workorder_kbs')
                    ->field('id,title,url')
                    ->where('id', 'in', $kbsIds)
                    ->where('status', '1')
                    ->where('deletetime', null)
                    ->where('id', '<>', $id)
                    ->order('weigh desc')
                    ->limit($limit)
                    ->select();
            }
        }

        if (!$recKbs) {
            $recKbs = Db::name('workorder_kbs')
                ->field('id,title')
                ->where('status', '1')
                ->where('deletetime', null)
                ->where('id', '<>', $id)
                ->order('weigh desc,views desc')
                ->limit($limit)
                ->select();
        }
        return $recKbs;
    }

    public function engineerViewed($order)
    {
        if ($order->status == 1) {
            $order->status = 2;
            $order->allowField(true)->save();

            $record = [
                'order_id'     => $order->id,
                'engineer_id'  => $order->engineer_id,
                'message_type' => 3,
                'message'      => __('The engineer has viewed your submitted questions')
            ];
            Records::create($record);

            // 发送通知
            $this->mailNotice($order, 'user_order_handle', __('[work order is already being processed]') . $order->title, __('Work order:%s the engineer has reviewed the problem you submitted and is processing it', [$order->title]));
            $this->smsNotice($order, 'user_order_handle');
            return true;
        }

        return false;
    }

    /**
     * 工单详情处理
     */
    public function orderInfoHandle($order, $isUser, $isCurrentEngineer)
    {
        $nowTime = time();

        // 下次可催办时间
        $urging_rate    = (int)($this->workorderConfig['urging_rate'] * 60);
        $nextUrgingTime = (int)$order->lasturgingtime + $urging_rate;

        $order->title = $order->title ?? __('Untitled');

        // 标记工程师处理中
        if ($isCurrentEngineer) {
            $this->engineerViewed($order);
        }

        $order->urging = false;
        $order->close  = false;
        if ($isUser && $order->status <= 2 && $nextUrgingTime <= $nowTime && $order->engineer_id && $this->workorderConfig['user_urging']) {
            $order->urging = true;
        }
        if ($order->status <= 3) {
            $order->close = true;
        }

        $order->status = $this->handleStatus($order->status, $isCurrentEngineer);

        // 处理用户头像
        if ($order->user) {
            $order->user->avatar = $order->user->avatar ? cdnurl($order->user->avatar, true) : (function_exists('letter_avatar') ? letter_avatar($order->user->nickname) : cdnurl('/assets/img/avatar.png', true));
        }

        $basicField = [];// 工单基本信息字段
        $allField   = $order->getFields($order, 0);
        foreach ($allField as $field) {
            if ($field['isbasicinfo']) {
                $field['value'] = self::fieldValue($field, $field['value']);
                $basicField[]   = $field;
            }
        }

        if ($isCurrentEngineer) {
            $basicField[] = [
                'title' => __('Submit user'),
                'value' => $order->user->nickname
            ];

            if (!$this->workorderConfig['engineer_close']) {
                $order->close = false;
            }
        }

        return [
            'order'      => $order,
            'basicField' => $basicField
        ];
    }

    public static function fieldValue($field, $value)
    {
        if ($field['type_list'] == 'switch') {
            return $value ? __('open') : __('close');
        }

        if ($value == '') {
            return '';
        }
        $listField = ['select', 'selects', 'checkbox', 'radio'];
        if (in_array($field['type_list'], $listField)) {
            if (is_array($field['values_list'])) {
                $valueTmp = '';
                if (!is_array($value)) {
                    $value = explode(',', $value);
                }
                foreach ($value as $item) {
                    $valueTmp .= isset($field['values_list'][$item]) ? $field['values_list'][$item] . '，' : '';
                }
                return trim($valueTmp, '，');
            }
        }

        return $value;
    }


    /**
     * 关闭工单
     */
    public function closeOrder($order, $isCurrentEngineer)
    {
        $nowTime = time();
        if ($order->status == 4 || $order->status == 5) {
            return ['code' => 0, 'msg' => __('The work order has been closed!')];
        }

        if ($isCurrentEngineer && ($this->workorderConfig['engineer_close'] == 0)) {
            return ['code' => 0, 'msg' => __('The engineer was not allowed to close the work order~')];
        }

        $order->status = 4;
        $order->save();

        $timeStatistics = Db::name('workorder_time_statistics')
            ->where('order_id', $order->id)
            ->where('type', 0)
            ->where('time_consum', null)
            ->find();
        if ($timeStatistics) {
            // 记录结单耗时
            Db::name('workorder_time_statistics')
                ->where('id', $timeStatistics['id'])
                ->update([
                    'endtime'     => $nowTime,
                    'time_consum' => $nowTime - $timeStatistics['starttime'],
                    'engineer_id' => $order->engineer_id,// 防转移，冲正为当前工程师
                ]);
        }

        return ['code' => 1, 'msg' => __('Work order closed successfully~')];
    }

    /**
     * 催单
     */
    public function urgingOrder($order)
    {
        $nowTime = time();
        if (!$this->workorderConfig['user_urging']) {
            return ['code' => 0, 'msg' => __('Reminder function not enabled~')];
        }

        // 下次可催办时间-在isPost内有使用
        $urging_rate    = (int)($this->workorderConfig['urging_rate'] * 60);
        $nextUrgingTime = (int)$order->lasturgingtime + $urging_rate;

        if ($nextUrgingTime <= $nowTime) {
            $order->lasturgingtime = $nowTime;
            $order->save();

            $order->title = $order->title ?? __('Untitled');
            $this->mailNotice($order, 'engineer_urging', __('[work order reminder]') . $order->title, __('Dear engineer, work order:%s, the user hopes you will reply as soon as possible.', [$order->title]));
            $this->smsNotice($order, 'engineer_urging');

            return ['code' => 1, 'msg' => __('Reminder message sent successfully~')];
        } else {
            return ['code' => 0, 'msg' => __('Urge message sent frequently!')];
        }
    }

    /**
     * 获取一个工单的聊天记录和所有工程师
     */
    public function orderRecords($id, $engineer = 0)
    {
        // 沟通记录
        $records = Records::where('order_id', $id)
            ->order('createtime asc')
            ->select();

        // 共有哪些工程师
        $engineers = [];
        if ($engineer) {
            $engineers[$engineer] = $engineer;
        }

        foreach ($records as $record) {
            if ($record->engineer_id) {
                $engineers[$record->engineer_id] = $record->engineer_id;
            }
            if ($record->engineer && $record->engineer->user) {
                $record->engineer->user->avatar = $record->engineer->user->avatar ? cdnurl($record->engineer->user->avatar, true) : (function_exists('letter_avatar') ? letter_avatar($record->engineer->title) : cdnurl('/assets/img/avatar.png', true));
            }
        }

        $engineers          = Engineer::select($engineers);
        $engineerInfoConfig = Engineer::getEngineerInfoConfig();
        foreach ($engineers as $engineer) {
            if (!$engineer->introduce) {
                $engineer->introduce = ($engineer->user && $engineer->user->bio) ? $engineer->user->bio : '';
            }
            $engineer->all_order_number = in_array('all_order_number', $engineerInfoConfig) ? $engineer->all_order_number : false;
            $engineer->wx               = in_array('wx', $engineerInfoConfig) ? $engineer->wx : false;
            $engineer->qq               = in_array('qq', $engineerInfoConfig) ? $engineer->qq : false;
            if ($engineer->user) {
                $engineer->user->mobile = in_array('mobile', $engineerInfoConfig) ? $engineer->user->mobile : false;
                $engineer->user->email  = in_array('email', $engineerInfoConfig) ? $engineer->user->email : false;
                $engineer->user->avatar = $engineer->user->avatar ? cdnurl($engineer->user->avatar, true) : (function_exists('letter_avatar') ? letter_avatar($engineer->title) : cdnurl('/assets/img/avatar.png', true));
            }
        }

        return [
            'records'   => $records,
            'engineers' => $engineers
        ];
    }

    public function handleStatus($status, $isEngineer = false)
    {
        $colors = [
            'info',
            'info',
            'warning',
            'danger',
            'danger',
            'success'
        ];

        $statusLang = __('Status ' . $status);
        if ($isEngineer) {
            switch ($status) {
                case 3:
                    $statusLang = __('Waiting for user feedback');
                    break;
                case 4:
                    $statusLang = __('To be evaluated by users');
                    break;
                case 2:
                    $statusLang = __('Waiting for your reply');
                    break;
            }
        }

        return [
            'pc'       => '<span class="text-' . $colors[$status] . '">' . $statusLang . '</span>',
            'h5'       => '<span class="text-' . $colors[$status] . '">[' . $statusLang . ']</span>',
            'original' => $statusLang,
            'number'   => $status
        ];
    }
}